﻿using Microsoft.Win32.SafeHandles;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;

namespace UtilZ.Dotnet.Ex.Base.BaseEx
{
    /// <summary>
    /// ISO辅助类
    /// </summary>
    public class ISOHelper
    {
        /// <summary>
        /// 10兆一个块写
        /// </summary>
        private const int _WRITE_BLOCK_SIZE = 10240;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="directory"></param>
        /// <param name="isoFilePath"></param>
        public static void Write(string directory, string isoFilePath)
        {
            byte[] buffer = new byte[_WRITE_BLOCK_SIZE];
            DirectoryInfo dirInfo = new DirectoryInfo(directory);
            using (FileStream isoStream = new FileStream(isoFilePath, FileMode.Create, FileAccess.Write, FileShare.Write))
            {
                PrimitiveWrite(isoStream, dirInfo, buffer);
            }
        }

        private static void PrimitiveWrite(FileStream isoStream, DirectoryInfo dirInfo, byte[] buffer)
        {
            FileInfo[] fileInfos = dirInfo.GetFiles();
            if (fileInfos.Length > 0)
            {
                int readLenth = buffer.Length;
                long modLen;

                foreach (var fileInfo in fileInfos)
                {
                    using (var fs = fileInfo.OpenRead())
                    {
                        while (fs.Position < fs.Length)
                        {
                            modLen = fs.Length - fs.Position;
                            if (modLen < buffer.Length)
                            {
                                readLenth = (int)modLen;
                            }

                            fs.Read(buffer, 0, readLenth);
                            isoStream.Write(buffer, 0, readLenth);
                        }
                    }
                }
            }

            DirectoryInfo[] subDirInfos = dirInfo.GetDirectories();
            if (subDirInfos.Length > 0)
            {
                foreach (var subDirInfo in subDirInfos)
                {
                    PrimitiveWrite(isoStream, subDirInfo, buffer);
                }
            }
        }


        //public void Convert(string driverName, string isoFileName)
        //{
        //    ///打开数据
        //    UnmanagedDriverLoader loader = new UnmanagedDriverLoader(driverName);
        //    FileStream hDriver = new FileStream(loader.Handle, FileAccess.Read);
        //    FileStream hIso = new FileStream(isoFileName, FileMode.Create, FileAccess.Write, FileShare.Write);

        //    ///10兆一个块
        //    int bufferSize = 10240;
        //    byte[] buffer = new byte[bufferSize];

        //    long cdSize = GetCDROMSize(driverName);
        //    ///计算块的分页大小
        //    long icount = (long)(cdSize / bufferSize);
        //    if ((cdSize % bufferSize) != 0)
        //    {
        //        icount++;
        //    }

        //    long length = bufferSize;

        //    hDriver.Seek(0, SeekOrigin.Begin);
        //    hIso.Seek(0, SeekOrigin.Begin);

        //    ///遍历块写到文件
        //    for (long i = 0; i < icount; i++)
        //    {
        //        hDriver.Read(buffer, 0, (int)length);
        //        hIso.Write(buffer, 0, (int)length);

        //        length = cdSize - hDriver.Position;

        //        if (OnProgress != null)
        //        {
        //            OnProgress(this, 0, cdSize, hIso.Length);
        //        }
        //        if (length > bufferSize)
        //        {
        //            length = bufferSize;
        //        }
        //    }

        //    hDriver.Close();
        //    hIso.Close();
        //}
    }

    internal class UnmanagedFileLoader : IDisposable
    {
        public const short FILE_ATTRIBUTE_NORMAL = 0x80;
        public const short INVALID_HANDLE_VALUE = -1;
        public const uint GENERIC_READ = 0x80000000;
        public const uint GENERIC_WRITE = 0x40000000;
        public const uint CREATE_NEW = 1;
        public const uint CREATE_ALWAYS = 2;
        public const uint OPEN_EXISTING = 3;

        // Use interop to call the CreateFile function.
        // For more information about CreateFile,
        // see the unmanaged MSDN reference library.
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        private static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess,
          uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition,
          uint dwFlagsAndAttributes, IntPtr hTemplateFile);



        private SafeFileHandle handleValue = null;


        public UnmanagedFileLoader(string Path)
        {
            Load(Path);
        }


        public void Load(string Path)
        {
            if (Path == null || Path.Length == 0)
            {
                throw new ArgumentNullException("Path");
            }

            // Try to open the file.
            handleValue = CreateFile(Path, GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);

            // If the handle is invalid,
            // get the last Win32 error 
            // and throw a Win32Exception.
            if (handleValue.IsInvalid)
            {
                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
            }
        }



        public SafeFileHandle Handle
        {
            get
            {
                return handleValue;
                //// If the handle is valid,
                //// return it.
                //if (!handleValue.IsInvalid)
                //{
                //    return handleValue;
                //}
                //else
                //{
                //    return null;
                //}
            }

        }

        public void Dispose()
        {
            this.handleValue.Dispose();
        }
    }
}
